function tuxingyanshi()
    % 多普勒效应模拟
    % 情况1: 声源运动，两个静止的观察者
    % 情况2: 声源静止，一个运动的观察者

    % 清除变量和命令窗口
    clc;
    clear;

    %% 参数设置
    c = 5;                    % 波速 (m/s)
    v_initial = 2;            % 初始速度 (m/s)
    duration = 20;            % 模拟持续时间 (秒)
    dt = 0.02;                % 时间步长 (秒)
    epsilon = 1e-3;           % 防止除以零的小值
    max_frequency = 1000;     % 最大频率显示值 (Hz)

    %% 初始位置
    source_pos = [0, 0];          % 声源初始位置
    observer1_pos = [40, 0];      % 观察者1初始位置 (情况1)
    observer2_pos = [-40, 0];     % 观察者2初始位置 (情况1)
    observer3_pos = [40, 0];      % 观察者3初始位置 (情况2)

    %% 创建图形窗口
    fig = figure('Name', '多普勒效应可视化', 'NumberTitle', 'off', ...
                 'Units', 'normalized', 'Position', [0.1 0.1 0.8 0.8], ...
                 'CloseRequestFcn', @close_fig);

    % 设置坐标轴
    ax = axes('Parent', fig, 'Units', 'normalized', 'Position', [0.05 0.1 0.6 0.8]);
    axis(ax, 'equal');
    xlim(ax, [-100, 100]);
    ylim(ax, [-100, 100]);
    xlabel(ax, 'X 位置 (m)');
    ylabel(ax, 'Y 位置 (m)');
    title(ax, '多普勒效应 - 声源与观察者运动产生的波前');
    hold(ax, 'on');
    grid(ax, 'on');

    %% 绘制声源和观察者
    h_source = plot(ax, source_pos(1), source_pos(2), 'ko', 'MarkerSize', 8, 'MarkerFaceColor', 'k', 'DisplayName', '声源');
    h_observer1 = plot(ax, observer1_pos(1), observer1_pos(2), 'bo', 'MarkerSize', 8, 'MarkerFaceColor', 'b', 'DisplayName', '观察者1');
    h_observer2 = plot(ax, observer2_pos(1), observer2_pos(2), 'ro', 'MarkerSize', 8, 'MarkerFaceColor', 'r', 'DisplayName', '观察者2');
    h_observer3 = plot(ax, observer3_pos(1), observer3_pos(2), 'go', 'MarkerSize', 8, 'MarkerFaceColor', 'g', 'DisplayName', '观察者3');
    set(h_observer3, 'Visible', 'off'); % 初始时隐藏观察者3

    %% 初始化波前
    wavefronts = {};
    wave_emit_times = [];

    %% 添加控件
    % 控制面板
    control_panel = uipanel('Parent', fig, 'Units', 'normalized', 'Position', [0.7 0.05 0.25 0.9], 'Title', '控制面板');

    % 情况选择按钮组
    bg = uibuttongroup('Parent', control_panel, 'Units', 'normalized', 'Position', [0.05 0.7 0.9 0.25], ...
                      'Title', '选择情况', 'SelectionChangedFcn', @scenario_selection);

    % 单选按钮
    rb1 = uicontrol(bg, 'Style', 'radiobutton', 'String', '情况1: 声源运动, 静止观察者', ...
                   'Units', 'normalized', 'Position', [0.1 0.6 0.8 0.3], 'HandleVisibility', 'off');
    rb2 = uicontrol(bg, 'Style', 'radiobutton', 'String', '情况2: 声源静止, 运动观察者', ...
                   'Units', 'normalized', 'Position', [0.1 0.1 0.8 0.3], 'HandleVisibility', 'off');
    % 设置默认选择
    rb1.Value = 1;

    % 滑块标签
    slider_label = uicontrol('Parent', control_panel, 'Style', 'text', 'String', '速度 (m/s)', ...
                             'Units', 'normalized', 'Position', [0.2 0.55 0.6 0.1], ...
                             'FontSize', 10, 'HorizontalAlignment', 'center');

    % 速度滑块
    speed_slider = uicontrol('Parent', control_panel, 'Style', 'slider', ...
                             'Min', -(c - epsilon), 'Max', (c - epsilon), 'Value', v_initial, ...
                             'Units', 'normalized', 'Position', [0.2 0.5 0.6 0.05], ...
                             'Callback', @set_speed);

    % 速度显示文本
    speed_text = uicontrol('Parent', control_panel, 'Style', 'text', 'String', ['速度: ' num2str(v_initial, '%.2f') ' m/s'], ...
                           'Units', 'normalized', 'Position', [0.2 0.4 0.6 0.05], ...
                           'FontSize', 10, 'HorizontalAlignment', 'center');

    % 开始和停止按钮
    start_button = uicontrol('Parent', control_panel, 'Style', 'pushbutton', 'String', '开始', ...
                             'Units', 'normalized', 'Position', [0.2 0.3 0.25 0.1], ...
                             'Callback', @start_simulation);

    stop_button = uicontrol('Parent', control_panel, 'Style', 'pushbutton', 'String', '停止', ...
                            'Units', 'normalized', 'Position', [0.55 0.3 0.25 0.1], ...
                            'Callback', @stop_simulation);

    % 声源频率显示（仅用于情况2）
    freq_source_text = text(ax, source_pos(1), source_pos(2)+10, '', ...
                            'Color', 'k', 'FontSize', 10, 'BackgroundColor', 'w', ...
                            'HorizontalAlignment', 'center', 'Tag', 'freq_source_text', 'Visible', 'off');

    %% 创建 handles 结构体
    handles = struct();
    handles.c = c;
    handles.v_initial = v_initial;
    handles.v_current = v_initial;
    handles.duration = duration;
    handles.dt = dt;
    handles.epsilon = epsilon;
    handles.max_frequency = max_frequency;
    handles.isRunning = false;
    handles.f_source = 20; % 声源频率 (Hz)
    handles.ax = ax;
    handles.h_source = h_source;
    handles.h_observer1 = h_observer1;
    handles.h_observer2 = h_observer2;
    handles.h_observer3 = h_observer3;
    handles.wavefronts = wavefronts;
    handles.wave_emit_times = wave_emit_times;
    handles.source_pos = source_pos;
    handles.observer1_pos = observer1_pos;
    handles.observer2_pos = observer2_pos;
    handles.observer3_pos = observer3_pos;
    handles.control_panel = control_panel;
    handles.bg = bg;
    handles.rb1 = rb1;
    handles.rb2 = rb2;
    handles.slider_label = slider_label;
    handles.speed_slider = speed_slider;
    handles.speed_text = speed_text;
    handles.start_button = start_button;
    handles.stop_button = stop_button;
    handles.freq_source_text = freq_source_text;
    handles.current_scenario = 1; % 默认选择情况1

    % 保存 handles
    guidata(fig, handles);

end  % 主函数结束

%% 回调函数和辅助函数

% 情况选择回调函数
function scenario_selection(src, event)
    handles = guidata(src);
    selected = event.NewValue.String;
    if strcmp(selected, '情况1: 声源运动, 静止观察者')
        handles.current_scenario = 1;
        set(handles.slider_label, 'String', '声源速度 (m/s)');
        set(handles.speed_slider, 'Min', -(handles.c - handles.epsilon), 'Max', (handles.c - handles.epsilon), 'Value', handles.v_initial);
        set(handles.speed_text, 'String', ['速度: ' num2str(handles.v_initial, '%.2f') ' m/s']);
        % 重置位置
        set(handles.h_source, 'XData', 0, 'YData', 0);
        set(handles.h_observer1, 'XData', 40, 'YData', 0, 'Visible', 'on');
        set(handles.h_observer2, 'XData', -40, 'YData', 0, 'Visible', 'on');
        set(handles.h_observer3, 'Visible', 'off'); % 隐藏观察者3
        set(handles.freq_source_text, 'Visible', 'off'); % 隐藏声源频率显示
        handles.source_pos = [0, 0];
        handles.observer1_pos = [40, 0];
        handles.observer2_pos = [-40, 0];
    elseif strcmp(selected, '情况2: 声源静止, 运动观察者')
        handles.current_scenario = 2;
        set(handles.slider_label, 'String', '观察者速度 (m/s)');
        set(handles.speed_slider, 'Min', -(handles.c - handles.epsilon), 'Max', (handles.c - handles.epsilon), 'Value', handles.v_initial);
        set(handles.speed_text, 'String', ['速度: ' num2str(handles.v_initial, '%.2f') ' m/s']);
        % 重置位置
        set(handles.h_source, 'XData', 0, 'YData', 0);
        set(handles.h_observer1, 'Visible', 'off'); % 隐藏观察者1
        set(handles.h_observer2, 'Visible', 'off'); % 隐藏观察者2
        set(handles.h_observer3, 'Visible', 'on'); % 显示观察者3
        set(handles.h_observer3, 'XData', 40, 'YData', 0); % 重置观察者3位置
        set(handles.freq_source_text, 'String', ['f_{source} = ' num2str(handles.f_source, '%.2f') ' Hz'], ...
                                     'Visible', 'on'); % 显示声源频率
        handles.source_pos = [0, 0];
        handles.observer3_pos = [40, 0];
    end
    guidata(src, handles);
end

% 速度滑块回调函数
function set_speed(src, ~)
    handles = guidata(src);
    handles.v_current = src.Value;
    % 更新速度显示
    set(handles.speed_text, 'String', ['速度: ' num2str(handles.v_current, '%.2f') ' m/s']);
    guidata(src, handles);
end

% 开始模拟回调函数
function start_simulation(~, ~)
    handles = guidata(gcf);

    if handles.isRunning
        return;
    end

    % 清除之前的波前和频率文本
    delete(findall(handles.ax, 'Type', 'line', 'Tag', 'wavefront'));
    delete(findall(handles.ax, 'Type', 'text', 'Tag', 'freq_text'));

    % 重置波前和发射时间
    handles.wavefronts = {};
    handles.wave_emit_times = [];

    % 重置观察者3的位置（重要）
    if handles.current_scenario == 2
        handles.observer3_pos = [40, 0];
        set(handles.h_observer3, 'XData', handles.observer3_pos(1), 'YData', handles.observer3_pos(2));
    end

    guidata(gcf, handles);

    % 设置运行状态并初始化开始时间
    handles.isRunning = true;
    handles.start_time = tic;
    guidata(gcf, handles);

    % 模拟循环
    while true
        % 检查图形和 handles 是否有效
        if ~ishandle(handles.ax)
            break;
        end

        handles = guidata(gcf);

        if ~isstruct(handles) || ~handles.isRunning
            break;
        end

        time_elapsed = toc(handles.start_time);

        if time_elapsed > handles.duration
            break;
        end

        v_current = handles.v_current; % 当前速度
        scenario = handles.current_scenario;

        % 每隔1秒发射一个波前
        if isempty(handles.wave_emit_times) || (time_elapsed - handles.wave_emit_times(end) >= 1)
            handles.wave_emit_times(end+1) = time_elapsed;
            wavefront = plot(handles.ax, NaN, NaN, 'k-', 'Tag', 'wavefront');
            handles.wavefronts{end+1} = wavefront;
            guidata(gcf, handles);
        end

        % 根据情况更新位置
        if scenario == 1
            % 情况1: 声源运动
            handles.source_pos(1) = v_current * time_elapsed;
            set(handles.h_source, 'XData', handles.source_pos(1), 'YData', handles.source_pos(2));
        elseif scenario == 2
            % 情况2: 观察者运动
            handles.observer3_pos(1) = handles.observer3_pos(1) + v_current * handles.dt;
            set(handles.h_observer3, 'XData', handles.observer3_pos(1), 'YData', handles.observer3_pos(2));
        end

        % 更新波前
        num_wavefronts = length(handles.wave_emit_times);
        for i = 1:num_wavefronts
            wave_radius = handles.c * (time_elapsed - handles.wave_emit_times(i));
            if wave_radius < 0
                continue;
            end

            theta = linspace(0, 2*pi, 200);
            if scenario == 1
                % 情况1: 声源运动
                x_center = handles.v_current * handles.wave_emit_times(i);
                y_center = 0;
            elseif scenario == 2
                % 情况2: 声源静止
                x_center = 0;
                y_center = 0;
            end
            x_wave = x_center + wave_radius * cos(theta);
            y_wave = y_center + wave_radius * sin(theta);

            if isvalid(handles.wavefronts{i})
                set(handles.wavefronts{i}, 'XData', x_wave, 'YData', y_wave);
            end
        end

        % 计算并显示频率
        if scenario == 1
            % 情况1: 声源运动
            f_observed1 = calculate_observed_frequency_moving_source(handles.source_pos, handles.observer1_pos, v_current, handles.c, handles.f_source, handles.epsilon, handles.max_frequency);
            f_observed2 = calculate_observed_frequency_moving_source(handles.source_pos, handles.observer2_pos, v_current, handles.c, handles.f_source, handles.epsilon, handles.max_frequency);
            % 显示频率
            delete(findall(handles.ax, 'Type', 'text', 'Tag', 'freq_text'));
            text(handles.ax, handles.observer1_pos(1), handles.observer1_pos(2)+10, sprintf('f_{obs1} = %.2f Hz', f_observed1), ...
                'Color', 'b', 'FontSize', 10, 'BackgroundColor', 'w', 'Tag', 'freq_text');
            text(handles.ax, handles.observer2_pos(1), handles.observer2_pos(2)+10, sprintf('f_{obs2} = %.2f Hz', f_observed2), ...
                'Color', 'r', 'FontSize', 10, 'BackgroundColor', 'w', 'Tag', 'freq_text');
        elseif scenario == 2
            % 情况2: 观察者运动
            v_observer = v_current; % 观察者速度
            f_observed3 = calculate_observed_frequency_moving_observer(handles.source_pos, handles.observer3_pos, v_observer, ...
                handles.c, handles.f_source, handles.epsilon, handles.max_frequency);
            % 显示频率
            delete(findall(handles.ax, 'Type', 'text', 'Tag', 'freq_text'));
            text(handles.ax, handles.observer3_pos(1), handles.observer3_pos(2)+10, sprintf('f_{obs3} = %.2f Hz', f_observed3), ...
                'Color', 'g', 'FontSize', 10, 'BackgroundColor', 'w', 'Tag', 'freq_text');
            % 调试输出
            disp(['[Debug] 时间: ', num2str(time_elapsed, '%.2f'), 's, 观察者速度: ', num2str(v_observer, '%.2f'), ' m/s, 接收频率: ', num2str(f_observed3, '%.2f'), ' Hz']);
        end

        % 更新 handles（特别是观察者3的位置）
        guidata(gcf, handles);

        % 更新图形
        drawnow;
        pause(handles.dt);
    end  % 模拟循环结束

    % 停止运行标志
    handles.isRunning = false;
    guidata(gcf, handles);
end

% 停止模拟回调函数
function stop_simulation(~, ~)
    handles = guidata(gcf);
    handles.isRunning = false;
    guidata(gcf, handles);
end

% 关闭窗口回调函数
function close_fig(src, ~)
    handles = guidata(src);
    if isstruct(handles) && handles.isRunning
        handles.isRunning = false;
        guidata(src, handles);
    end
    delete(src);
end

%% 频率计算函数
function f_observed = calculate_observed_frequency_moving_source(source_pos, observer_pos, v_source, c, f_source, epsilon, max_freq)
    % 计算声源运动时观察者接收到的频率
    r = observer_pos - source_pos;
    distance = norm(r);
    if distance == 0
        f_observed = f_source;
        return;
    end
    u = r / distance;
    v_source_vector = [v_source, 0];
    v_radial = dot(v_source_vector, u);

    % 防止除以零或负值
    if v_radial >= c - epsilon
        v_radial = c - epsilon;
    elseif v_radial <= -(c - epsilon)
        v_radial = -(c - epsilon);
    end

    % 计算频率
    f_observed = f_source * (c / (c - v_radial));

    % 确保频率在有效范围内
    if f_observed < 0 || isnan(f_observed) || isinf(f_observed)
        f_observed = 0;
    elseif f_observed > max_freq
        f_observed = max_freq;
    end
end

function f_observed = calculate_observed_frequency_moving_observer(source_pos, observer_pos, v_observer_x, c, f_source, epsilon, max_freq)
    % 计算观察者运动时接收到的频率
    % 观察者的速度矢量
    v_observer_vector = [v_observer_x, 0]; % 假设沿 x 轴运动

    % 从观察者指向声源的向量
    r = source_pos - observer_pos;
    distance = norm(r);
    if distance == 0
        f_observed = f_source;
        return;
    end
    u = r / distance; % 单位向量

    % 观察者速度的径向分量
    v_radial = dot(v_observer_vector, u);

    % 计算接收频率
    f_observed = f_source * ( (c + v_radial) / c );

    % 确保频率在有效范围内
    if f_observed < 0 || isnan(f_observed) || isinf(f_observed)
        f_observed = 0;
    elseif f_observed > max_freq
        f_observed = max_freq;
    end

    % 调试输出
    disp(['[Debug] 观察者速度: ', num2str(v_observer_x, '%.2f'), ...
          ' m/s, 径向速度: ', num2str(v_radial, '%.2f'), ' m/s, 接收频率: ', num2str(f_observed, '%.2f'), ' Hz']);
end
